﻿using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto.Modes;
using System.Text.RegularExpressions;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;

namespace UtilTools
{
    /// <summary>
    /// 安全类
    /// </summary>
    public static class Security
    {
        #region 随机数
        /// <summary>
        /// 生成随机字母与数字
        /// </summary>
        /// <param name="Length">生成长度</param>
        /// <param name="Sleep">是否要在生成前将当前线程阻止以避免重复</param>
        /// <returns></returns>
        public static String GetRandom(int Length, bool Sleep = false)
        {
            if (Sleep) { Thread.Sleep(3); }
            char[] Pattern = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
            String result = ""; int n = Pattern.Length;
            Random random = new Random(~unchecked((int)DateTime.Now.Ticks));
            for (int i = 0; i < Length; i++) { int rnd = random.Next(0, n); result += Pattern[rnd]; }
            return result;
        }
        /// <summary>
        /// 获取序列号
        /// </summary>
        /// <returns></returns>
        public static String GetSerialNumber()
        {
            String OutStr = String.Empty;
            using (Process rocess = new Process())
            {
                rocess.StartInfo.FileName = "cmd.exe";
                rocess.StartInfo.UseShellExecute = false;
                rocess.StartInfo.RedirectStandardInput = true;
                rocess.StartInfo.RedirectStandardOutput = true;
                rocess.StartInfo.RedirectStandardError = true;
                rocess.StartInfo.CreateNoWindow = true;
                rocess.Start(); Thread.Sleep(1000);
                rocess.StandardInput.WriteLine("WMIC DISKDRIVE GET SERIALNUMBER&EXIT");
                rocess.StandardInput.AutoFlush = true;
                OutStr = rocess.StandardOutput.ReadToEnd();
                rocess.WaitForExit();
            }
            List<String> SerialNumbers = new List<String>();
            String[] temps = OutStr.Split(new Char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            for (Int32 i = 0; i < temps.Length; i++) { SerialNumbers.Add(temps[i].Trim()); }
            if (SerialNumbers.Count < 4) { return null; }
            else if (String.IsNullOrWhiteSpace(SerialNumbers[4])) { return null; }
            else { return "ZY" + SerialNumbers[4].PadLeft(30, '0'); }
        }
        #endregion

        #region MD5加密方法
        /// <summary>
        /// MD5加密[大写]
        /// </summary>
        /// <param name="value">需要加密的字符串</param>
        /// <param name="IsShort">是否使用16位加密[默认:false]</param>
        /// <returns></returns>
        public static String MD5(String value, bool IsShort = false)
        {
            try
            {
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                byte[] bs = Encoding.UTF8.GetBytes(value);
                bs = md5.ComputeHash(bs);
                String CryptoStr;
                if (IsShort)
                {
                    CryptoStr = BitConverter.ToString(bs, 4, 8).Replace("-", "");
                }
                else
                {
                    StringBuilder s = new StringBuilder();
                    foreach (byte b in bs) { s.Append(b.ToString("x2")); }
                    CryptoStr = s.ToString();
                }
                return CryptoStr.ToUpper();
            }
            catch (Exception ex) { throw ex; }
        }
        /// <summary>
        /// MD5加密[大写]
        /// </summary>
        /// <param name="value">需要加密的字符串</param>
        /// <param name="IsShort">是否使用16位加密[默认:false]</param>
        /// <returns></returns>
        public static String MD5(Byte[] value, Boolean IsShort = false)
        {
            try
            {
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                Byte[] bs = md5.ComputeHash(value);
                String CryptoStr;
                if (IsShort) { CryptoStr = BitConverter.ToString(bs, 4, 8).Replace("-", ""); }
                else
                {
                    StringBuilder s = new StringBuilder();
                    foreach (Byte b in bs) { s.Append(b.ToString("x2")); }
                    CryptoStr = s.ToString();
                }
                return CryptoStr.ToUpper();
            }
            catch (Exception ex) { throw ex; }
        }
        #endregion

        #region Base64加密
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="value">需要加密的字符串</param>
        /// <returns></returns>
        public static String Base64Encrypt(String value)
        {
            return Base64Encrypt(Encoding.UTF8, value);
        }
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="encode">加密编码格式</param>
        /// <param name="value">需要加密的字符串</param>
        /// <returns></returns>
        public static String Base64Encrypt(Encoding encode, String value)
        {
            return Convert.ToBase64String(encode.GetBytes(value));
        }
        #endregion

        #region Base64解密
        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="value">解密字符串</param>
        /// <returns></returns>
        public static String Base64Decrypt(String value)
        {
            return Base64Decrypt(Encoding.UTF8, value);
        }
        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="encode">编码格式</param>
        /// <param name="value">解密字符串</param>
        /// <returns></returns>
        public static String Base64Decrypt(Encoding encode, String value)
        {
            byte[] bytes = Convert.FromBase64String(value);
            try
            {
                return encode.GetString(bytes);
            }
            catch { return value; }
        }
        #endregion

        #region Base64验证
        /// <summary>
        /// 验证是否是Base64格式字符串
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsBase64String(String str)
        {
            if (str != null)
            {
                return new Regex(@"[A-Za-z0-9\=\/\+]").IsMatch(str);
            }
            return true;
        }
        #endregion

        #region AES加密
        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="value">需要加密的字符串</param>
        /// <param name="Key">密钥</param>
        /// <param name="Model">密码模式 默认:ECB</param>
        /// <param name="Padding">填充类型 默认:PKCS7</param>
        /// <param name="IV">加密辅助向量 默认:null</param>
        /// <returns>加密后的字符串</returns>
        public static String AESEncrypt(String value, String Key, CipherMode Model = CipherMode.ECB, PaddingMode Padding = PaddingMode.PKCS7, String IV = "")
        {
            try
            {
                byte[] keyArray = Encoding.UTF8.GetBytes(Key);
                byte[] toEncryptArray = Encoding.UTF8.GetBytes(value);
                RijndaelManaged rDel = new RijndaelManaged();
                if (!String.IsNullOrWhiteSpace(IV)) { rDel.IV = Encoding.UTF8.GetBytes(IV); }
                rDel.Key = keyArray;
                rDel.Mode = Model;
                rDel.Padding = Padding;
                ICryptoTransform cTransform = rDel.CreateEncryptor();
                byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                rDel.Dispose();
                return Convert.ToBase64String(resultArray, 0, resultArray.Length);
            }
            catch (Exception ex) { throw ex; }
        }
        #endregion

        #region AES解密
        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="value">需要解密的字符串</param>
        /// <param name="Key">密钥</param>
        /// <param name="Model">密码模式 默认:ECB</param>
        /// <param name="Padding">填充类型 默认:PKCS7</param>
        /// <param name="IV">加密辅助向量 默认:null</param>
        /// <returns>解密后的字符串 异常返回null</returns>
        public static String AESDecrypt(String value, String Key, CipherMode Model = CipherMode.ECB, PaddingMode Padding = PaddingMode.PKCS7, String IV = "")
        {
            try
            {
                byte[] keyArray = Encoding.UTF8.GetBytes(Key);
                byte[] toEncryptArray = Convert.FromBase64String(value);
                RijndaelManaged rDel = new RijndaelManaged();
                rDel.Key = keyArray;
                if (!String.IsNullOrWhiteSpace(IV)) { rDel.IV = Encoding.UTF8.GetBytes(IV); }
                rDel.Mode = Model;
                rDel.Padding = Padding;
                ICryptoTransform cTransform = rDel.CreateDecryptor();
                byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
                return Encoding.UTF8.GetString(resultArray);
            }
            catch (Exception ex) { throw ex; }
        }
        #endregion

        #region SHA加密

        #region SHA-UTF-8加密
        /// <summary>
        /// SHA-UTF-8加密
        /// </summary>
        /// <param name="value">需要加密的字符串</param>
        /// <param name="shaType">加密方式</param>
        /// <returns></returns>
        public static String SHA(String value, SHAType shaType = SHAType.SHA1) => SHA(value, Encoding.UTF8, shaType);
        #endregion

        #region SHA指定编码加密
        /// <summary>
        /// SHA指定编码加密
        /// </summary>
        /// <param name="value">需要加密的字符串</param>
        /// <param name="encoding">编码格式</param>
        /// <param name="shaType">加密方式</param>
        /// <returns>返回加密后的字符串</returns>
        public static String SHA(String value, Encoding encoding, SHAType shaType = SHAType.SHA1)
        {
            try
            {
                HashAlgorithm ShaEn = null;
                switch (shaType)
                {
                    case SHAType.SHA256: ShaEn = new SHA256CryptoServiceProvider(); break;
                    case SHAType.SHA512: ShaEn = new SHA512CryptoServiceProvider(); break;
                    default: ShaEn = new SHA1CryptoServiceProvider(); break;
                }
                byte[] data = encoding.GetBytes(value);
                byte[] result = ShaEn.ComputeHash(data);
                ShaEn.Dispose();
                var _Result = BitConverter.ToString(result).Replace("-", "");
                return _Result;
            }
            catch (Exception ex) { throw ex; }
        }
        #endregion

        #region SHA加密枚举
        /// <summary>
        /// SHA加密类型
        /// </summary>
        public enum SHAType
        {
            /// <summary>
            /// SHA1
            /// </summary>
            SHA1,
            /// <summary>
            /// SHA256
            /// </summary>
            SHA256,
            /// <summary>
            /// SHA512
            /// </summary>
            SHA512
        }
        #endregion

        #endregion

        #region HMACSHA256
        /// <summary>
        /// HMACSHA256加密
        /// </summary>
        /// <param name="content"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static String HMACSHA256(String content, String key)
        {
            String result = "";
            var enc = Encoding.Default;
            byte[]
            baText2BeHashed = enc.GetBytes(content),
            baSalt = enc.GetBytes(key);
            System.Security.Cryptography.HMACSHA256 hasher = new HMACSHA256(baSalt);
            byte[] baHashedText = hasher.ComputeHash(baText2BeHashed);
            result = String.Join("", baHashedText.ToList().Select(b => b.ToString("x2")).ToArray());
            return result.ToUpper();
        }
        #endregion

        #region AES_256_GCM
        /// <summary>
        /// AES_256_GCM解密
        /// </summary>
        /// <param name="context">内容</param>
        /// <param name="key">秘钥</param>
        /// <param name="nonce">随机串</param>
        /// <param name="associated">随机串</param>
        /// <returns></returns>
        public static String GcmDecrypt(String context, String key, String nonce, String associated)
        {
            try
            {
                Byte[] keybytes = Encoding.UTF8.GetBytes(key);
                Byte[] noncebytes = Encoding.UTF8.GetBytes(nonce);
                Byte[] associatedbytes = Encoding.UTF8.GetBytes(associated);
                Byte[] contextbytes = Convert.FromBase64String(context);
                GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
                AeadParameters aeadParameters = new AeadParameters(new KeyParameter(keybytes), 128, noncebytes, associatedbytes);
                gcmBlockCipher.Init(false, aeadParameters);
                byte[] array2 = new byte[gcmBlockCipher.GetOutputSize(contextbytes.Length)];
                int num = gcmBlockCipher.ProcessBytes(contextbytes, 0, contextbytes.Length, array2, 0);
                gcmBlockCipher.DoFinal(array2, num);
                return Encoding.UTF8.GetString(array2);
            }
            catch (Exception ex) { throw ex; }
        }
        /// <summary>
        /// AES_256_GCM加密
        /// </summary>
        /// <param name="context">内容</param>
        /// <param name="key">秘钥</param>
        /// <param name="nonce">随机串</param>
        /// <param name="associated">随机串</param>
        /// <returns></returns>
        public static String GcmEncrypt(String context, String key, String nonce, String associated)
        {
            try
            {
                byte[] keybytes = Encoding.UTF8.GetBytes(key);
                byte[] noncebytes = Encoding.UTF8.GetBytes(nonce);
                byte[] contextbytes = Encoding.UTF8.GetBytes(context);
                byte[] associatedbytes = Encoding.UTF8.GetBytes(associated);
                GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
                AeadParameters aeadParameters = new AeadParameters(new KeyParameter(keybytes), 128, noncebytes, associatedbytes);
                gcmBlockCipher.Init(true, aeadParameters);
                byte[] array2 = new byte[gcmBlockCipher.GetOutputSize(contextbytes.Length)];
                int num = gcmBlockCipher.ProcessBytes(contextbytes, 0, contextbytes.Length, array2, 0);
                gcmBlockCipher.DoFinal(array2, num);
                return Convert.ToBase64String(array2, 0, array2.Length);

            }
            catch (Exception ex) { throw ex; }
        }
        #endregion

        #region DES 加密
        /// <summary>
        /// Des加密（Hex）
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥(8位任意字符)</param>
        /// <param name="encoding">字符编码</param>
        /// <param name="cipher">运算模式</param>
        /// <param name="padding">填充模式</param>
        /// <returns></returns>
        public static String DesEncryptToHexString(String encryptString, String encryptKey, Encoding encoding, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7)
        {
            var keyBytes = encoding.GetBytes(encryptKey);
            var inputBytes = encoding.GetBytes(encryptString);
            var outputBytes = EncryptToDesBytes(inputBytes, keyBytes, cipher, padding);
            var sBuilder = new StringBuilder();
            foreach (var b in outputBytes)
            {
                sBuilder.Append(b.ToString("X2"));//
            }
            return sBuilder.ToString();
        }

        /// <summary>
        /// Des加密（base64）
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥(8位任意字符)</param>
        /// <param name="encoding">字符编码</param>
        /// <param name="cipher">运算模式</param>
        /// <param name="padding">填充模式</param>
        /// <returns></returns>
        public static String DesEncryptToBase64String(String encryptString, String encryptKey, Encoding encoding, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.Zeros)
        {
            var keyBytes = encoding.GetBytes(encryptKey);
            var inputBytes = encoding.GetBytes(encryptString);
            var outputBytes = EncryptToDesBytes(inputBytes, keyBytes, cipher, padding);
            return Convert.ToBase64String(outputBytes);
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="encryptBytes">待加密的字节数组</param>
        /// <param name="keyBytes">加密密钥字节数组</param>
        /// <param name="cipher">运算模式</param>
        /// <param name="padding">填充模式</param>
        /// <returns></returns>
        public static byte[] EncryptToDesBytes(byte[] encryptBytes, byte[] keyBytes, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7)
        {
            var des = new DESCryptoServiceProvider
            {
                Key = keyBytes,
                IV = keyBytes,
                Mode = cipher,
                Padding = padding
            };
            var outputBytes = des.CreateEncryptor().TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);
            return outputBytes;
        }
        #endregion

        #region DES 解密
        /// <summary>
        /// 解密（Hex）
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥</param>
        /// <param name="encoding">字符编码</param>
        /// <param name="cipher">运算模式</param>
        /// <param name="padding">填充模式</param>
        /// <returns></returns>
        public static String DesDecryptByHexString(String decryptString, String decryptKey, Encoding encoding, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7)
        {
            var keyBytes = encoding.GetBytes(decryptKey);
            var inputBytes = new byte[decryptString.Length / 2];
            for (var i = 0; i < inputBytes.Length; i++)
            {
                inputBytes[i] = Convert.ToByte(decryptString.Substring(i * 2, 2), 16);
            }
            var outputBytes = DecryptByDesBytes(inputBytes, keyBytes, cipher, padding);
            return encoding.GetString(outputBytes).TrimEnd('\0');
        }
        /// <summary>
        /// 解密（Base）
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥</param>
        /// <param name="encoding">字符编码</param>
        /// <param name="cipher">运算模式</param>
        /// <param name="padding">填充模式</param>
        /// <returns></returns>
        public static String DesDecryptByBase64String(String decryptString, String decryptKey, Encoding encoding, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7)
        {
            var keyBytes = encoding.GetBytes(decryptKey);
            var inputBytes = Convert.FromBase64String(decryptString);
            var outputBytes = DecryptByDesBytes(inputBytes, keyBytes, cipher, padding);
            return encoding.GetString(outputBytes).TrimEnd('\0');
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="decryptBytes">待解密的字节数组</param>
        /// <param name="keyBytes">解密密钥字节数组</param>
        /// <param name="cipher">运算模式</param>
        /// <param name="padding">填充模式</param>
        /// <returns></returns>
        public static byte[] DecryptByDesBytes(byte[] decryptBytes, byte[] keyBytes, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7)
        {
            var des = new DESCryptoServiceProvider
            {
                Key = keyBytes,
                IV = keyBytes,
                Mode = cipher,
                Padding = padding
            };
            var outputBytes = des.CreateDecryptor().TransformFinalBlock(decryptBytes, 0, decryptBytes.Length);
            return outputBytes;
        }
        #endregion

        #region 异或校验
        private static UInt32[] CRC32Calculator(UInt32 poly)
        {
            UInt32 crc;
            UInt32[] Crc32Table = new UInt32[256];
            for (UInt32 i = 0; i < 256; i++)
            {
                crc = i;
                for (UInt32 j = 8; j > 0; j--)
                {
                    if ((crc & 1) != 1) { crc >>= 1; }
                    else { crc = (crc >> 1) ^ poly; }
                }
                Crc32Table[i] = crc;
            }
            return Crc32Table;
        }
        private static UInt32[] CRC32MPEG2Calculator(UInt32 poly)
        {
            UInt32 crc;
            UInt32[] Crc32Table = new UInt32[256];
            for (UInt32 i = 0; i < 256; i++)
            {
                crc = i << 24;
                for (UInt32 j = 0; j < 8; j++)
                {
                    if ((crc & 0x80000000) == 0) { crc <<= 1; }
                    else { crc = (crc << 1) ^ poly; }
                }
                Crc32Table[i] = crc;
            }
            return Crc32Table;
        }

        /// <summary>
        /// 异或校验
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static String BCC(this String str)
        {
            try
            {
                Int32 code = 0; Char[] chars = str.ToCharArray();
                for (Int32 i = 0; i < chars.Length; i++) { code ^= Convert.ToInt32(chars[i]); }
                return code.ToString("X");
            }
            catch { return null; }
        }
        /// <summary>
        /// 异或校验
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static String BCC(this Byte[] bytes)
        {
            try
            {
                Int32 code = 0;
                for (Int32 i = 0; i < bytes.Length; i++) { code ^= bytes[i]; }
                return code.ToString("X");
            }
            catch { return null; }
        }

        /// <summary>
        /// 循环冗余校验(CRC8)
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static String CRC8(this String str)
        {
            try
            {
                Int32 crc = 0;
                for (Int32 i = 1; i < str.Length / 2; i++)
                {
                    String hex = str.Substring(i * 2, 2);
                    if (i == 1)
                    {
                        String phex = str.Substring((i - 1) * 2, 2);
                        crc = (Byte)Convert.ToInt32(phex, 16) ^ (Byte)Convert.ToInt32(hex, 16);
                    }
                    else { crc = (Byte)crc ^ (Byte)Convert.ToInt32(hex, 16); }
                }
                return Convert.ToString(crc, 16).ToUpper();
            }
            catch { return null; }
        }

        /// <summary>
        /// 循环冗余校验(CRC16)
        /// </summary>
        /// <param name="data"></param>
        /// <param name="poly"></param>
        /// <param name="init"></param>
        /// <param name="xorout"></param>
        /// <param name="refin"></param>
        /// <param name="refout"></param>
        /// <returns></returns>
        public static Byte[] CRC16(this Byte[] data, UInt32 poly, UInt16 init, UInt16 xorout = 0, Boolean refin = true, Boolean refout = true)
        {
            UInt32 crc = init;
            Byte[] bytes = new Byte[2];
            poly = refin ? CRCREV(poly, 16) : poly;
            for (Int32 i = 0; i < data.Length; i++)
            {
                crc ^= data[i];
                for (Int32 j = 0; j < 8; j++)
                {
                    UInt32 tmp = crc & 1;
                    crc >>= 1;
                    crc &= 0x7FFF;
                    if (tmp == 1) { crc ^= poly; }
                    crc &= 0xFFFF;
                }
            }
            crc ^= xorout;
            if (!refout) { crc = CRCREV(crc, 16); }
            bytes[0] = (Byte)(crc & 0xFF);
            bytes[1] = (Byte)((crc >> 8) & 0xFF);
            return bytes;
        }

        /// <summary>
        /// 循环冗余校验(CRC32)
        /// </summary>
        /// <param name="data"></param>
        /// <param name="poly"></param>
        /// <param name="init"></param>
        /// <param name="xorout"></param>
        /// <param name="refin"></param>
        /// <param name="refout"></param>
        /// <returns></returns>
        public static Byte[] CRC32(this Byte[] data, UInt32 poly, UInt32 init, UInt32 xorout = 0, Boolean refin = false, Boolean refout = false)
        {
            UInt32 crc = init;
            Int32 len = data.Length;
            Byte[] bytes = new Byte[4];
            poly = refin ? CRCREV(poly, 32) : poly;
            UInt32[] Crc32Table = refin ? CRC32Calculator(poly) : CRC32MPEG2Calculator(poly);
            for (Int32 i = 0; i < len; i++)
            {
                if (refin) { crc = (crc >> 8) ^ Crc32Table[(crc & 0xFF) ^ data[i]]; }
                else { crc = (crc << 8) ^ Crc32Table[((crc >> 24) & 0xFF) ^ data[i]]; }
            }
            crc ^= xorout;
            if (refout) { crc = CRCREV(crc, 32); }
            bytes[0] = (Byte)(crc & 0xFF);
            bytes[1] = (Byte)((crc >> 8) & 0xFF);
            bytes[2] = (Byte)((crc >> 16) & 0xFF);
            bytes[3] = (Byte)((crc >> 24) & 0xFF);
            return bytes;
        }

        /// <summary>
        /// 按位取反
        /// </summary>
        /// <param name="x"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static UInt32 CRCREV(this UInt32 x, UInt32 len)
        {
            UInt32 b = 0;
            for (Int32 i = 0; i < len; i++)
            {
                b = (b << 1) | (x & 1); x >>= 1;
            }
            return b;
        }
        #endregion
    }
}
